package com.xmlt.core.template.instance;

import javax.xml.xpath.XPathExpressionException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.xmlt.core.template.Template;
import com.xmlt.core.template.TemplateException;
import com.xmlt.core.template.TemplateManager;
import com.xmlt.core.template.TemplateParameter;
import com.xmlt.core.template.Utils;

public class InstanceFactory {
	
	public static AbstractInstance newInstance(Document d, TemplateManager manager, String ref) throws TemplateException {
		Element root = d.getDocumentElement();
		return new Instance(root, d, manager, null, ref);
	}
	
	public static AbstractInstance newInstance(Element paramElement, Template t, TemplateManager tm, TemplateParameter tp, AbstractInstance parent) throws TemplateException {
		AbstractInstance inst = null;
		if (tp.isMultiple()) {
			inst = new MultiInstance(paramElement, tm, t, tp, parent);
		} else {
			if (tp == null || !tp.isValid())
				throw new TemplateException("Found null or invalid template parameter in instance factory");
			
			if (tp.isValue()) {
				inst = new Value(paramElement, tm, tp, parent);
			} else if (tp.isLink()) {
				// instance node is inside the param node
				try {
					Element instEl = (Element) Utils.evaluateXPath(paramElement, "instance").item(0);
					if (instEl != null) {
						inst = new Instance(instEl, tm, tp, parent, null);
						tm.registerInstance((Instance) inst);
					}
					else {
						String parentPath = parent.getPath() == null? "<root node>" : parent.getPath();
						throw new TemplateException(parentPath + " has null link in " + tp.getName());
					}
				} catch (XPathExpressionException e1) {
					throw new TemplateException(e1);
				}
			} else if (tp.isReference()) {
				// instance node is inside the param node
				try {
					Element instEl = (Element) Utils.evaluateXPath(paramElement, "instance").item(0);
					if (instEl != null) {
						inst  = new InstanceReference(instEl, tm, tp, parent);
					}
				} catch (XPathExpressionException e1) {
					throw new TemplateException(e1);
				}
			}
		}
		return inst;
	}
	
	public static AbstractInstance newMultiInstance(Element e, Template t, TemplateManager tm, TemplateParameter tp, AbstractInstance parent) throws TemplateException {
		AbstractInstance inst = null;
		if (tp.isValue()) {
			inst = new Value(e, tm, tp, parent);
		} else if (tp.isLink()) {
			inst = new Instance(e, tm, tp, parent, null);
			tm.registerInstance((Instance) inst);
		} else if (tp.isReference()) {
			inst = new InstanceReference(e, tm, tp, parent);
		}
		return inst;
	}
}
